﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;

namespace GrayParrot.Infrastructure
{
    [Serializable]
    public class WithExceptionHandling : OnMethodBoundaryAspect
    {
        Type m_currentType = null;

        public WithExceptionHandling()
        {

        }

        public override void CompileTimeInitialize(System.Reflection.MethodBase method, AspectInfo aspectInfo)
        {
            base.CompileTimeInitialize(method, aspectInfo);

            m_currentType = method.DeclaringType;
        }

        public override void OnException(MethodExecutionArgs args)
        {
            if (args.Exception.GetType() == typeof(System.Data.Entity.Validation.DbEntityValidationException))
            {
                System.Data.Entity.Validation.DbEntityValidationException dbEx = (System.Data.Entity.Validation.DbEntityValidationException)args.Exception;
                Exception raise = args.Exception;
                foreach (var validationErrors in dbEx.EntityValidationErrors)
                {
                    foreach (var validationError in validationErrors.ValidationErrors)
                    {
                        string message = string.Format("{0}:{1}", validationErrors.Entry.Entity.ToString(), validationError.ErrorMessage);
                        // raise a new exception nesting
                        // the current instance as InnerException
                        raise = new InvalidOperationException(message, raise);
                    }
                }

                args.Exception = raise;
            }

            /* cattura i parametri di input al metodo (anche complessi) */
            Dictionary<string, object> m_args = new Dictionary<string, object>();

            for (int i = 0; i < args.Arguments.Count(); i++)
            {
                string name = args.Method.GetParameters()[i].Name;
                object obj = args.Arguments.GetArgument(i);

                m_args.Add(name, obj);
            }

            string m_inputParameters = JsonConvert.SerializeObject(m_args);
            /* cattura i parametri di input al metodo (anche complessi) */


            /* se l'attributo è applicato ad un classe che deriva da FacadeBase, aggiorniamo in automatico il campo LastException */
            //if ((args.Instance != null) && (args.Instance.GetType().BaseType == typeof(FacadeBase)))
            //{
            if ((m_currentType != null) && (m_currentType.BaseType == typeof(FacadeBase)))
            {
                FacadeBase t = (FacadeBase)args.Instance;
                t.LastException = args.Exception;
            }

            string msg = string.Format("{0} Error.", args.Method.Name);

            GrayParrot.Logging.Logger.InputArguments = m_inputParameters;
            GrayParrot.Logging.Logger.For(m_currentType).Error(msg, args.Exception);

            args.FlowBehavior = FlowBehavior.Continue;
        }
    }
}
